﻿//==============================================================================
// File: IPropertyContainer.cs
// Created: 2010-04-25
// Author: Piotr Włodek
//==============================================================================
// This file is a part of MAMMOTH project.
// Copyright (C) 2010 AGH University of Science and Technology, Krakow.
// https://caribou.iisg.agh.edu.pl/trac/mammoth
//
// Mammoth is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// Mammoth is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with WpfRcp. If not, see http://www.gnu.org/licenses/.
//==============================================================================

using System.Collections.Generic;
using WpfRcp.PropertyModel.Core;
using WpfRcp.PropertyModel.Scope;
using WpfRcp.PropertyModel.Validation;

namespace WpfRcp.PropertyModel
{
    /// <summary>
    /// Defines an interface for a property container.
    /// </summary>
    public interface IPropertyContainer : IDynamicPropertyRegistry, IValidatable, INotifyObjectStateChanged
    {
        /// <summary>
        /// Gets a <see cref="PropertyContainerType"/> which represents this type.
        /// </summary>
        PropertyContainerType PropertyContainerType { get; }

        /// <summary>
        /// Gets or sets a value of a given property.
        /// </summary>
        /// <param name="index">Property for which value is being retrieved.</param>
        /// <returns>Value of a given property.</returns>
        object this[MetaProperty index] { get; set; }

        /// <summary>
        /// Gets or sets a value of a given property.
        /// </summary>
        /// <param name="index">Property for which value is being retrieved.</param>
        /// <returns>Value of a given property.</returns>
        object this[string index] { get; set; }

        /// <summary>
        /// Gets a value of a given property.
        /// </summary>
        /// <param name="property"><see cref="MetaProperty"/> which identifies the
        /// property a value is retrieved for.</param>
        /// <returns>Value of a given property.</returns>
        object GetValue(MetaProperty property);

        /// <summary>
        /// Gets a value of a given property.
        /// </summary>
        /// <param name="property">Property name which identifies the
        /// property a value is retrieved for.</param>
        /// <returns>Value of a given property.</returns>
        object GetValue(string property);

        /// <summary>
        /// Sets a value for a given property.
        /// </summary>
        /// <param name="property">Property name which identifies the
        /// property a value is set for.</param>
        /// <param name="value">The value being set.</param>
        void SetValue(string property, object value);

        /// <summary>
        /// Sets a value for a given property.
        /// </summary>
        /// <param name="metaProperty"><see cref="MetaProperty"/> which identifies the
        /// property a value is set for.</param>
        /// <param name="value">The value being set.</param>
        void SetValue(MetaProperty metaProperty, object value);

        /// <summary>
        /// Sets a value for a given property.
        /// </summary>
        /// <param name="propertyKey"><see cref="MetaPropertyKey"/> which identifies the
        /// read-only property a value is set for.</param>
        /// <param name="value">The value being set.</param>
        void SetValue(MetaPropertyKey propertyKey, object value);

        /// <summary>
        /// Clears the value for a given property.
        /// </summary>
        /// <param name="metaProperty"><see cref="MetaProperty"/> which identifies the
        /// property for which the value is being cleared.</param>
        void ClearValue(MetaProperty metaProperty);

        /// <summary>
        /// Clears the value for a given property.
        /// </summary>
        /// <param name="property">Property name which identifies the
        /// property for which the value is being cleared.</param>
        void ClearValue(string property);

        /// <summary>
        /// Method used for checking if a given property has a default value.
        /// </summary>
        /// <param name="metaProperty"><see cref="MetaProperty"/> identifying
        /// property to check.</param>
        /// <returns>True if given property has a default value set. False otherwise.</returns>
        bool HasDefaultValue(MetaProperty metaProperty);

        /// <summary>
        /// Method used for checking if a given property has a default value.
        /// </summary>
        /// <param name="propertyName">Property name identifying
        /// property to check.</param>
        /// <returns>True if given property has a default value set. False otherwise.</returns>
        bool HasDefaultValue(string propertyName);

        /// <summary>
        /// Checks if the property has a valid value.
        /// </summary>
        /// <param name="property">Name of the property to be checked.</param>
        /// <returns>True if the property has a valid value. False otherwise.</returns>
        bool HasValidValue(string property);

        /// <summary>
        /// Checks if the property has a valid value.
        /// </summary>
        /// <param name="metaProperty"><see cref="MetaProperty"/> instance which identifies a property.</param>
        /// <returns>True if the property has a valid value. False otherwise.</returns>
        bool HasValidValue(MetaProperty metaProperty);

        /// <summary>
        /// Validates given property and updates <see cref="IPropertyContainer"/>'s validation status.
        /// </summary>
        /// <param name="metaProperty">Property to be validated.</param>
        /// <remarks>You can use this method to manually trigger property validation whenever
        /// property's value changes.</remarks>
        void ValidateProperty(MetaProperty metaProperty);

        /// <summary>
        /// Performs full property and object validation and updates <see cref="IValidatable.IsValid"/> property.
        /// </summary>
        void Validate();

        /// <summary>
        /// Returns a collection of all meta properties registered for this instance.
        /// </summary>
        /// <returns>Collection of all meta properties registered for this instance.</returns>
        MetaPropertyCollection GetProperties();

        /// <summary>
        /// Gets a meta property for a property specified by name, or null, if property does not exist.
        /// </summary>
        /// <param name="name">Name of the property.</param>
        /// <returns>Meta property for a property specified by name, or null, if property does not exist.</returns>
        MetaProperty GetProperty(string name);

        /// <summary>
        /// Adds this property container to a specified scope.
        /// </summary>
        /// <param name="scope">Scope this object is being added to.</param>
        /// <returns>Scope this object is being added to.</returns>
        IPropertyScope AddScope(IPropertyScope scope);

        /// <summary>
        /// Removes this property container from a specified scope.
        /// </summary>
        /// <param name="scope">Scope this object is being removed from.</param>
        void RemoveScope(IPropertyScope scope);

        /// <summary>
        /// Compares content of two <see cref="IPropertyContainer"/> instances.
        /// </summary>
        /// <param name="compareTarget">Target which this instance is compared to.</param>
        /// <returns>True if instances contain the same matchable content.</returns>
        /// <remarks>
        /// This method uses only properties which are designated for matching.
        /// Both value and reference types are compared using Equals method rather than
        /// ContentEquals. You should avoid redirecting Equals method to the ContentEquals
        /// method as this might lead to circular comparisons.
        /// </remarks>
        bool ContentEquals(IPropertyContainer compareTarget);

        /// <summary>
        /// Compares content of two <see cref="IPropertyContainer"/> instances.
        /// </summary>
        /// <param name="compareTarget">Target which this instance is compared to.</param>
        /// <param name="propertyNames">Properties to be used for comparison. Bear in mind that
        /// given parameters don't have to be marked as matchable.</param>
        /// <returns>True if instances contain the same matchable content.</returns>
        /// <remarks>
        /// This method uses only properties which are designated for matching.
        /// Both value and reference types are compared using Equals method rather than
        /// ContentEquals. You should avoid redirecting Equals method to the ContentEquals
        /// method as this might lead to circular comparisons.
        /// </remarks>
        bool ContentEquals(IPropertyContainer compareTarget, params string[] propertyNames);

        /// <summary>
        /// Compares content of two <see cref="IPropertyContainer"/> instances.
        /// </summary>
        /// <param name="compareTarget">Target which this instance is compared to.</param>
        /// <param name="propertyNames">Properties to be used for comparison. Bear in mind that
        /// given parameters don't have to be marked as matchable.</param>
        /// <returns>True if instances contain the same matchable content.</returns>
        /// <remarks>
        /// This method uses only properties which are designated for matching.
        /// Both value and reference types are compared using Equals method rather than
        /// ContentEquals. You should avoid redirecting Equals method to the ContentEquals
        /// method as this might lead to circular comparisons.
        /// </remarks>
        bool ContentEquals(IPropertyContainer compareTarget, IEnumerable<string> propertyNames);

        /// <summary>
        /// Returns a proxied interface which defines properties present
        /// on the <see cref="PropertyContainer"/>.
        /// </summary>
        /// <typeparam name="TInterface">Type of the interface to be returned.</typeparam>
        /// <returns>proxied interface which defines properties present
        /// on the <see cref="PropertyContainer"/>, or null if the interface
        /// cannot be satisfied.</returns>
        TInterface GetDuck<TInterface>() where TInterface : class;
    }
}